package org.hilo.boot.core.db;

import java.lang.reflect.Field;

import org.springframework.core.NamedThreadLocal;

/**
 * ThreadLocal DataSourceKey
 *
 * @author zollty
 * @since 2018-02-17
 */
public final class DataSourceKeyHolder {
    private static final ThreadLocal<String> KEY_HOLDER = 
            new NamedThreadLocal<String>("current dynamic datasource");
    
    private DataSourceKeyHolder() {
    }

    /**
     * 设置数据源lookupKey
     */
    public static void setLookupKey(String lookupKey) {
        if (lookupKey == null || lookupKey.length() == 0) {
            KEY_HOLDER.set(null);
        } else {
            KEY_HOLDER.set(lookupKey);
        }
    }

    /**
     * 获取数据源lookupKey
     */
    public static String getCurrentKey() {
        return KEY_HOLDER.get();
    }

    /**
     * 清除数据源lookupKey
     */
    public static void removeCurrentKey() {
        KEY_HOLDER.remove();
    }
    
    /**
     * 从AOP代理对象中获得原对象的类型
     */
    public static final Class<?> getMapperClassFromProxy(Object proxyObject) {
        Class<?> clazz = proxyObject.getClass();
        if (clazz.getSimpleName().startsWith("$Proxy")) {
            try {
                clazz = clazz.getSuperclass();
                Field hField = clazz.getDeclaredField("h");
                hField.setAccessible(true);
                Object hObject = hField.get(proxyObject);
                
                if (hObject instanceof org.apache.ibatis.binding.MapperProxy) {
                    Class<?> dynamicProxyClass = hObject.getClass();
                    Field mField = dynamicProxyClass.getDeclaredField("mapperInterface");
                    mField.setAccessible(true);
                    return (Class<?>) mField.get(hObject);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }
    
    /**
     * 从AOP代理对象中获得原对象的类型
     */
    @SuppressWarnings("unchecked")
    static final <T> T getBeanFromProxy2(T proxyObject) {
        Class<?> clazz = proxyObject.getClass();
        if(clazz.getSimpleName().startsWith("$Proxy")) {
            try {
                clazz = clazz.getSuperclass();
                Field hField = clazz.getDeclaredField("h");
                hField.setAccessible(true);
                Object hObject = hField.get(proxyObject);

                Class<?> dynamicProxyClass = hObject.getClass();
                Field advisedField = dynamicProxyClass.getDeclaredField("advised");
                advisedField.setAccessible(true);
                Object advisedObject = advisedField.get(hObject);

                Class<?> advisedSupportClass = advisedObject.getClass().getSuperclass().getSuperclass();
                Field targetField = advisedSupportClass.getDeclaredField("targetSource");
                targetField.setAccessible(true);
                Object targetObject = targetField.get(advisedObject);

                Class<?> targetSourceClass = targetObject.getClass();
                Field targetClassField = targetSourceClass.getDeclaredField("target");
                targetClassField.setAccessible(true);
                return (T) targetClassField.get(targetObject);
            } catch (SecurityException e) {
                e.printStackTrace();
            } catch (NoSuchFieldException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
